package com.gitee.wsl.compose.chart.sample

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.absolutePadding
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.unit.dp
import com.gitee.wsl.common.ui.draw.style.LineStyle
import com.gitee.wsl.compose.chart.ChartLayout
import com.gitee.wsl.compose.chart.ExperimentalKoalaPlotApi
import com.gitee.wsl.compose.chart.SelectChangedListener
import com.gitee.wsl.compose.chart.SelectCheck

import com.gitee.wsl.compose.chart.generateHueColorPalette
import com.gitee.wsl.compose.chart.legend.Flow
import com.gitee.wsl.compose.chart.legend.Legend
import com.gitee.wsl.compose.chart.legend.LegendLocation
import com.gitee.wsl.compose.chart.xy.XYGraph
import com.gitee.wsl.compose.chart.xy.XYGraphScope
import com.gitee.wsl.compose.chart.xy.axis.model.CategoryAxisModel
import com.gitee.wsl.compose.chart.xy.axis.model.FloatLinearAxisModel
import com.gitee.wsl.compose.chart.xy.line.LinePlot
import com.gitee.wsl.compose.chart.xy.model.PointEntry
import com.gitee.wsl.compose.modifier.layout.VerticalRotation
import com.gitee.wsl.compose.modifier.layout.rotateVertically
import com.gitee.wsl.compose.ui.widget.Symbol
import com.gitee.wsl.compose.modifier.layout
import com.gitee.wsl.ext.set.addOrRemove
import kotlin.math.ceil

val xyLineSampleView = object : SampleView {
    override val name: String = "XY Line"

    override val thumbnail = @Composable {
        ThumbnailTheme {
            XYSamplePlot(true, name)
        }
    }

    override val content: @Composable () -> Unit = @Composable {
        XYSamplePlot(false, "Rainfall")
    }
}

private val colorMap = buildMap {
    val colors = generateHueColorPalette(RainData.rainfall.size)
    var i = 0
    RainData.rainfall.forEach {
        put(it.key, colors[i++])
    }
}

@OptIn(ExperimentalKoalaPlotApi::class)
@Composable
@Suppress("MagicNumber")
private fun XYSamplePlot(thumbnail: Boolean, title: String) {
    val selectedIndex = remember {  mutableStateListOf<Int>() }
    val selectChangedListener: SelectChangedListener = {
        selectedIndex.addOrRemove(it)
        println("select index: $it value:${fibonacci[it]}")
    }

    ChartLayout(
        modifier = paddingMod,
        title = { ChartTitle(title) },
        legend = { selected,listener -> LegendView(thumbnail,selected,listener) },
        legendLocation = LegendLocation.BOTTOM,
        selectCheck =  selectedIndex::contains,
        selectChangedListener = selectChangedListener,
    ) {
        XYGraph(
            xAxisModel = CategoryAxisModel(RainData.months),
            yAxisModel = FloatLinearAxisModel(
                0f..(ceil(RainData.max / 50.0) * 50.0).toFloat(),
                minimumMajorTickSpacing = 50.dp,
            ),
            xAxisLabels = {
                if (!thumbnail) {
                    AxisLabel(it, Modifier.padding(top = 2.dp))
                }
            },
            xAxisTitle = {
                if (!thumbnail) {
                    Box(
                        modifier = Modifier.fillMaxWidth(),
                        contentAlignment = Alignment.Center
                    ) {
                        AxisTitle("Month")
                    }
                }
            },
            yAxisLabels = {
                if (!thumbnail) AxisLabel(it.toString(), Modifier.absolutePadding(right = 2.dp))
            },
            yAxisTitle = {
                if (!thumbnail) {
                    Box(
                        modifier = Modifier.fillMaxHeight(),
                        contentAlignment = Alignment.TopStart
                    ) {
                        AxisTitle(
                            "Rainfall (mm)",
                            modifier = Modifier
                                .layout {
                                    rotateVertically(VerticalRotation.COUNTER_CLOCKWISE)
                                }
                                .padding(bottom = padding)
                        )
                    }
                }
            }
        ) {
            RainData.rainfall.entries.sortedBy { it.key }.forEachIndexed {index, (city, rain) ->
                chart(
                    city,
                    rain.mapIndexed { index, d ->
                        PointEntry(RainData.months[index], d.toFloat())
                    },
                    thumbnail,
                    selected = selectedIndex.contains(index)
                )
            }
        }
    }
}

@OptIn(ExperimentalKoalaPlotApi::class)
@Composable
private fun XYGraphScope<String, Float>.chart(
    city: String,
    data: List<PointEntry<String, Float>>,
    thumbnail: Boolean,
    selected:Boolean
) {
    LinePlot(
        data = data,
        lineStyle = LineStyle(
            brush = SolidColor(colorMap[city] ?: Color.Black),
            strokeWidth = 2.dp
        ),
        symbol = { point,selected ->
            Symbol(
                shape = CircleShape,
                size = 8.dp * if (selected) 1.5f else 1f,
                fillBrush = SolidColor(colorMap[city] ?: Color.Black),
                modifier = Modifier.then(
                    if (!thumbnail) {
                        Modifier.hoverableElement {
                            HoverSurface { Text(point.y.toString()) }
                        }
                    } else {
                        Modifier
                    }
                )
            )
        },
        selected = selected
    )
}

@OptIn(ExperimentalKoalaPlotApi::class)
@Composable
private fun LegendView(thumbnail: Boolean = false,selectCheck: SelectCheck,selectChangedListener: SelectChangedListener?) {
    val cities = RainData.rainfall.keys.sorted()

    if (!thumbnail) {
        Surface(shadowElevation = 2.dp) {
            Legend.Flow(
                itemCount = cities.size,
                symbol = { i,selected ->
                    Symbol(
                        modifier = Modifier.size(padding),
                        fillBrush = SolidColor(colorMap[cities[i]] ?: Color.Black)
                    )
                },
                label = { i,selected,listener ->
                    Text(cities[i])
                },
                modifier = paddingMod,
                selectCheck = selectCheck,
                selectChangedListener = selectChangedListener
            )
        }
    }
}
